

/**
 * @file CSDetectorWL.hpp
 */

#ifndef GPSTK_CSDetectorWL_HPP
#define GPSTK_CSDetectorWL_HPP


#include <deque>
#include "ProcessingClass.hpp"
#include "CSDetectorLC.hpp"
#include "SatID.hpp"

namespace gpstk
{

      /** @addtogroup GPSsolutions */
      //@{

   class CSDetectorWL : public ProcessingClass
   {
   public:

         /// Default constructor, setting default parameters.
      CSDetectorWL() 
          : firstTime(true),
            deltaTMax(91.0), useLLI(true),
            polyOrder(1),
            ionoDrift(0.01), threshold(0.86),
            usePolyFit(true), sampleInterval(30.0),
            pLCDetector(NULL)
      {
          minBufferSize = 4;
          maxBufferSize = 8;
      };


         /** Returns a satTypeValueMap object, adding the new data generated
          *  when calling this object.
          *
          * @param epoch     Time of observations.
          * @param gData     Data object holding the data.
          * @param epochflag Epoch flag.
          */
      virtual satTypeValueMap& Process( const CommonTime& epoch,
                                        satTypeValueMap& gData )
         noexcept(false);

      virtual void setLCDetector(CSDetectorLC& detector)
      {
          pLCDetector = &detector;
      };

      virtual double getDeltaTMax() const
      { return deltaTMax; };

      virtual CSDetectorWL& setDeltaTMax(const double& maxDelta);


      virtual double getSampleInterval() const
      { 
          return sampleInterval; 
      };

      virtual CSDetectorWL& setSampleInterval(const double interval)
      {
          sampleInterval = interval;
          return (*this);
      };

      virtual CSDetectorWL& setPolyOrder(const double order)
      {
          polyOrder = order;
          if(polyOrder==1)
          {
              minBufferSize = 4;
              maxBufferSize = 6;
          }
          else if(polyOrder==2)
          {
              minBufferSize = 5;
              maxBufferSize = 8;
          }


          return (*this);
      };

               /** Method to get the maximum buffer size for data, in samples.
          */
      virtual double getMaxBufferSize() const
      { return maxBufferSize; };

         /** Method to set the maximum buffer size for data, in samples.
          *
          * @param maxBufSize      Maximum buffer size for data, in samples.
          *
          * \warning You must not set a value under minBufferSize, which
          * usually is 5.
          */
      virtual CSDetectorWL& setMaxBufferSize(const int& maxBufSize)
      {
                   // Don't allow buffer sizes less than minBufferSize
          if (maxBufSize >= minBufferSize)
          {
             maxBufferSize = maxBufSize;
          }
          else
          {
             maxBufferSize = minBufferSize;
          }

          return (*this);
      };

         /// Method to know if the LLI check is enabled or disabled.
      virtual bool getUseLLI() const
      { return useLLI; };


         /** Method to set whether the LLI indexes will be used as an aid
          *  or not.
          *
          * @param use   Boolean value enabling/disabling LLI check
          */
      virtual CSDetectorWL& setUseLLI(const bool& use)
      { useLLI = use; return (*this); };


      virtual CSDetectorWL& setType(TypeID type, SatelliteSystem::Systems sys)
      {   
          wlType = type;
          satSys = sys; 
          
          if(satSys == SatelliteSystem::GPS)
          {
              if(wlType == TypeID::WL12)
              {
                  prefitType = TypeID::prefitWL12;
                  diffPrefitType = TypeID::diffPrefitWL12;
                  diffIonoType = TypeID::diffIonoL1;
                  diffPostType = TypeID::diffPostfitWL12;
                  waveLength = WL12_WAVELENGTH_GPS ;
              }
              else if(wlType == TypeID::WL25)
              {
                  prefitType = TypeID::prefitWL25;
                  diffPrefitType = TypeID::diffPrefitWL25;
                  diffIonoType = TypeID::diffIonoL1;
                  diffPostType = TypeID::diffPostfitWL25;
                  waveLength = WL25_WAVELENGTH_GPS ;
              }
          }
          else
          {
              cerr << "CSDetectorWL:: dont's support this system " << endl;
              exit(-1);
          }

          return (*this); 
      };

         /** Returns a gnnsRinex object, adding the new data generated when
          *  calling this object.
          *
          * @param gData    Data object holding the data.
          */
      virtual void Process(gnssRinex& gData)
         noexcept(false);

      virtual void getEpochDiffData(satTypeValueMap& sData);


      virtual int getDetection(SatID& sat,
                               const CommonTime& epoch,
                               double& deltaWL,
                               int& csFlag,
                               int& csValue);

      virtual int Robust(  Vector<double>& prefitResiduals,
                           Matrix<double>& designMatrix,
                           Matrix<double>& weightMatrix,
                           Vector<double>& postfitResiduals,
                           Vector<double>& standResidual,
                           Vector<double>& solution,
                           Matrix<double>& covMatrix,
                           double&         sig,
                           Vector<int>&    outlierVector)
         noexcept(false);


      virtual int getMaxIndex( Vector<double>& residual,
                               Vector<int>& flagVec);


      virtual int getMinIndex( Vector<double>& residual,
                               Vector<int>& flagVec);


      virtual void setCSDataStream(std::ofstream& stream)
      {
          pCSDataStream = &stream;
      };


         /// Returns a string identifying this object.
      virtual std::string getClassName(void) const;


         /// Destructor
      virtual ~CSDetectorWL() {};


   private:

      int polyOrder;
      bool firstTime;
      TypeID wlType;
      SatelliteSystem::Systems satSys;

      TypeID prefitType;
      TypeID diffPrefitType;
      TypeID diffIonoType;
      TypeID diffPostType;
      double waveLength;

      bool usePolyFit;

      /// Maximum interval of time allowed between two successive epochs,
      /// in seconds.
      double deltaTMax;

      /// Maximum buffer size.
      int maxBufferSize;

      int minBufferSize;

      double ionoDrift;

      double threshold;

         /// This field tells whether to use or ignore the LLI indexes as
         /// an aid.
      bool useLLI;

      double sampleInterval;

         /// A structure used to store filter data for a SV.
      struct filterData
      {
            // Default constructor initializing the data in the structure
         filterData()
         {};

         std::deque<CommonTime> epochDeque;
         std::deque<double> deltaDeque;  //  WL(t) - WL(t-1) = deltaIono + lambdaNw*deltaNw;
      };

      typedef std::map<SatID, filterData> satDeltaMap;

      CSDetectorLC* pLCDetector;

      // for deltaWL-fit and predict delta-WL
      satDeltaMap deltaData;

      satTypeValueMap stvDataPrev;

      std::ofstream* pCSDataStream;


  }; // End of class 'CSDetectorWL'

      //@}

}  // End of namespace gpstk

#endif   // GPSTK_CSDetectorWL_HPP
